package com.sojson.project.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sojson.base.impl.BaseUser;
import com.sojson.constant.ConstantMessageSystemTemplate;
import com.sojson.constant.IpConfig;
import com.sojson.constant.Lock;
import com.sojson.enums.EBalanceCount;
import com.sojson.enums.EBalanceDivideType;
import com.sojson.enums.EBalanceTotalType;
import com.sojson.enums.EBalanceType;
import com.sojson.enums.EFirstOrderType;
import com.sojson.enums.EMessageSystemType;
import com.sojson.enums.EOrderStatusHotel;
import com.sojson.enums.core.EGeneralStatus;
import com.sojson.enums.core.EGeneralYesNo;
import com.sojson.enums.core.EModuleNo;
import com.sojson.enums.core.EOrderCloseType;
import com.sojson.enums.core.EOrderHotelCloseType;
import com.sojson.enums.core.EOrderStatus;
import com.sojson.enums.core.EPayStatus;
import com.sojson.enums.core.ERefundsStatus;
import com.sojson.enums.core.EUserCouponStatus;
import com.sojson.project.dao.BalanceLogDao;
import com.sojson.project.dao.HotelDao;
import com.sojson.project.dao.HotelOrderDao;
import com.sojson.project.dao.HotelOrderRoomDao;
import com.sojson.project.dao.HotelOrderUserDao;
import com.sojson.project.dao.HotelRoomDao;
import com.sojson.project.dao.UserCouponDao;
import com.sojson.project.entity.bo.CouponUseGoodsParam;
import com.sojson.project.entity.bo.CouponUseResponse;
import com.sojson.project.entity.bo.OrderGoodsParam;
import com.sojson.project.entity.bo.OrderParam;
import com.sojson.project.entity.bo.OrderStoreParam;
import com.sojson.project.entity.bo.OrderUserParam;
import com.sojson.project.entity.po.BalanceLog;
import com.sojson.project.entity.po.Brokerage;
import com.sojson.project.entity.po.Hotel;
import com.sojson.project.entity.po.HotelOrder;
import com.sojson.project.entity.po.HotelOrderRoom;
import com.sojson.project.entity.po.HotelOrderUser;
import com.sojson.project.entity.po.HotelRoom;
import com.sojson.project.entity.po.UserCoupon;
import com.sojson.project.entity.vo.HotelOrderVo;
import com.sojson.project.service.BrokerageService;
import com.sojson.project.service.CouponService;
import com.sojson.project.service.HotelOrderService;
import com.sojson.project.service.MessageSystemService;
import com.sojson.project.sys.user.dao.UserDao;
import com.sojson.project.sys.user.entity.po.User;
import com.sojson.util.ArithUtil;
import com.sojson.util.DateUtil;
import com.sojson.util.ExpUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.id.IdUtil;
import com.sojson.util.pay.PayUtil;
import com.sojson.util.pay.wx.constant.WxConstant;
import com.sojson.util.token.TokenUtil;

/**
 * 入驻记录信息Service实现类
 *
 * @author liu
 * @date 2021-07-02
 */
@Service
public class HotelOrderServiceImpl implements HotelOrderService {

    @Lazy
    @Autowired
    private HotelOrderServiceImpl hotelOrderService;
    @Autowired
    private BrokerageService brokerageService;
    @Autowired
    private MessageSystemService messageSystemService;
    @Autowired
    private CouponService couponService;
    @Resource
    private UserDao userDao;
    @Resource
    private HotelDao hotelDaoImpl;
    @Resource
    private HotelRoomDao hotelRoomDaoImpl;
    @Resource
    private HotelOrderDao hotelOrderDaoImpl;
    @Resource
    private HotelOrderRoomDao hotelOrderRoomDaoImpl;
    @Resource
    private HotelOrderUserDao hotelOrderUserDaoImpl;
    @Resource
    private UserCouponDao userCouponDaoImpl;
    @Resource
    private BalanceLogDao balanceLogDaoImpl;

    /**
     * 单条插入
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int insert(HotelOrder hotelOrder) {
        int insert = hotelOrderDaoImpl.insert(hotelOrder);
        return insert;
    }

    /**
     * 批量插入
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int insertList(HotelOrder hotelOrder) {
        int insertList = hotelOrderDaoImpl.insertList(hotelOrder.getHotelOrders());
        return insertList;
    }

    /**
     * 通过对象批量删除(物理删除)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int deleteByDto(HotelOrder hotelOrder) {
        int deleteByDto = hotelOrderDaoImpl.deleteByDto(hotelOrder);
        return deleteByDto;
    }

    /**
     * 统计全部数量
     *
     * @return
     */
    @Override
    public int countAll() {
        int countAll = hotelOrderDaoImpl.countAll();
        return countAll;
    }

    /**
     * 查询所有
     *
     * @return
     */
    @Override
    public List<HotelOrder> listAll() {
        List<HotelOrder> findAll = hotelOrderDaoImpl.listAll();
        return findAll;
    }

    /**
     * 根据对象统计数量
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int countByDto(HotelOrder hotelOrder) {
        int countByDto = hotelOrderDaoImpl.countByDto(hotelOrder);
        return countByDto;
    }

    /**
     * 根据对象查询
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public List<HotelOrder> listByDto(HotelOrder hotelOrder) {
        List<HotelOrder> findByDto = hotelOrderDaoImpl.listByDto(hotelOrder);
        return findByDto;
    }

    /**
     * 通过id删除(物理删除)
     *
     * @param id
     * @return
     */
    @Override
    public int deleteById(Integer id) {
        int deleteById = hotelOrderDaoImpl.deleteById(id);
        return deleteById;
    }

    /**
     * 通过id数组删除(物理删除)
     *
     * @param ids
     * @return
     */
    @Override
    public int deleteByIds(Integer[] ids) {
        int deleteByIds = hotelOrderDaoImpl.deleteByIds(ids);
        return deleteByIds;
    }

    /**
     * 通过id更新(全部更新)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateAllById(HotelOrder hotelOrder) {
        int updateAllById = hotelOrderDaoImpl.updateAllById(hotelOrder);
        return updateAllById;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateAllByIdList(HotelOrder hotelOrder) {
        int updateAllByIdList = hotelOrderDaoImpl.updateAllByIdList(hotelOrder);
        return updateAllByIdList;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容不相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateDtoListAllById(HotelOrder hotelOrder) {
        int updateDtoListAllById = hotelOrderDaoImpl.updateDtoListAllById(hotelOrder.getHotelOrders());
        return updateDtoListAllById;
    }

    /**
     * 通过id更新(局部更新)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateById(HotelOrder hotelOrder) {
        int updateById = hotelOrderDaoImpl.updateById(hotelOrder);
        return updateById;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateByIdList(HotelOrder hotelOrder) {
        int updateByIdList = hotelOrderDaoImpl.updateByIdList(hotelOrder);
        return updateByIdList;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容不相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateDtoListById(HotelOrder hotelOrder) {
        int updateDtoListById = hotelOrderDaoImpl.updateDtoListById(hotelOrder.getHotelOrders());
        return updateDtoListById;
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @Override
    public HotelOrder findById(String id) {
        HotelOrder findById = hotelOrderDaoImpl.findById(id);
        return findById;
    }

    /**
     * 通过id数组查询
     *
     * @param ids
     * @return
     */
    @Override
    public List<HotelOrder> findByIds(Integer[] ids) {
        List<HotelOrder> findByIds = hotelOrderDaoImpl.findByIds(ids);
        return findByIds;
    }

    /**
     * 通过对象查询id列表
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public List<Integer> findIdByDto(HotelOrder hotelOrder) {
        List<Integer> findIdByDto = hotelOrderDaoImpl.findIdByDto(hotelOrder);
        return findIdByDto;
    }

    /**
     * 通过no删除(物理删除)
     *
     * @param no
     * @return
     * @throws IOException
     */
    @Override
    public int deleteByNo(String no) throws IOException {
        HotelOrder findByNo = hotelOrderDaoImpl.findByNo(no);
        if (StringUtil.isBlankObject(findByNo)) {
            return 0;
        }
        String noUser = findByNo.getNoUser();
        if (!noUser.equals(TokenUtil.getUserId())) {
            ExpUtil.throwEx("只能删除自己的订单！");
        }
        Integer status = findByNo.getStatus();
        if (status != EOrderStatusHotel.CLOSE_YES.getCode() || status != EOrderStatusHotel.RETU_YES.getCode()
            || status != EOrderStatusHotel.COMMENT_NO.getCode()) {
            ExpUtil.throwEx("订单未结束！");
        }

        int deleteByNo = hotelOrderDaoImpl.deleteByNo(no);
        return deleteByNo;
    }

    /**
     * 通过no数组删除(物理删除)
     *
     * @param nos
     * @return
     */
    @Override
    public int deleteByNos(String[] nos) {
        int deleteByNos = hotelOrderDaoImpl.deleteByNos(nos);
        return deleteByNos;
    }

    /**
     * 通过no更新(全部更新)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateAllByNo(HotelOrder hotelOrder) {
        int updateAllByNo = hotelOrderDaoImpl.updateAllByNo(hotelOrder);
        return updateAllByNo;
    }

    /**
     * 通过no列表更新(全部更新)(更新内容相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateAllByNoList(HotelOrder hotelOrder) {
        int updateAllByNoList = hotelOrderDaoImpl.updateAllByNoList(hotelOrder);
        return updateAllByNoList;
    }

    /**
     * 通过no列表更新(全部更新)(更新内容不相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateDtoListAllByNo(HotelOrder hotelOrder) {
        int updateDtoListAllByNo = hotelOrderDaoImpl.updateDtoListAllByNo(hotelOrder.getHotelOrders());
        return updateDtoListAllByNo;
    }

    /**
     * 通过no更新(局部更新)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateByNo(HotelOrder hotelOrder) {
        int updateByNo = hotelOrderDaoImpl.updateByNo(hotelOrder);
        return updateByNo;
    }

    /**
     * 通过no列表更新(局部更新)(更新内容相同)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateByNoList(HotelOrder hotelOrder) {
        int updateByNoList = hotelOrderDaoImpl.updateByNoList(hotelOrder);
        return updateByNoList;
    }

    /**
     * 通过no列表更新(局部更新)(更新内容不相同)
     *
     * @param hotelOrders
     * @return
     */
    @Override
    public int updateDtoListByNo(HotelOrder hotelOrder) {
        int updateDtoListByNo = hotelOrderDaoImpl.updateDtoListByNo(hotelOrder.getHotelOrders());
        return updateDtoListByNo;
    }

    /**
     * 通过no查询
     *
     * @param no
     * @return
     */
    @Override
    public HotelOrder findByNo(String no) {
        HotelOrder findByNo = hotelOrderDaoImpl.findByNo(no);
        return findByNo;
    }

    /**
     * 通过no数组查询
     *
     * @param nos
     * @return
     */
    @Override
    public List<HotelOrder> findByNos(String[] nos) {
        List<HotelOrder> findByNos = hotelOrderDaoImpl.findByNos(nos);
        return findByNos;
    }

    /**
     * 通过对象查询no列表
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public List<String> findNoByDto(HotelOrder hotelOrder) {
        List<String> findNoByDto = hotelOrderDaoImpl.findNoByDto(hotelOrder);
        return findNoByDto;
    }

    /**
     * 清空数据(物理清空)
     */
    @Override
    public int clear() {
        return hotelOrderDaoImpl.clear();
    }

    /**
     * 根据对象查询
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public List<HotelOrderVo> list(HotelOrderVo hotelOrder) {
        if (StringUtil.isBlankObjectListOne(hotelOrder.getStartTimeVo(), hotelOrder.getEndTimeVo())) {
            hotelOrder.setStartTimeVo(null);
            hotelOrder.setEndTimeVo(null);
        }
        return hotelOrderDaoImpl.list(hotelOrder);
    }

    /**
     * 通过no查询
     *
     * @param no
     * @return
     */
    @Override
    public HotelOrderVo getInfo(String no) {
        return hotelOrderDaoImpl.getInfo(no);
    }

    /**
     * 取消订单
     *
     * @param no
     * @return
     * @throws Exception
     */
    @Override
    public int cancel(String no) throws Exception {
        synchronized (Lock.ORDER_STATUS_HOTEL) {
            return hotelOrderService.cancelGo(no);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public int cancelGo(String no) throws Exception {
        int updatePartialById = 0;
        // 查询订单
        HotelOrder findByNo = hotelOrderService.findByNo(no);

        // 查看订单是否存在
        if (StringUtil.isBlankObject(findByNo)) {
            ExpUtil.throwEx("订单不存在！");
        }

        // 查看订单是否可以取消
        Date startTime = findByNo.getStartTime();
        startTime.setHours(18);
        Integer status = findByNo.getStatus();
        if (status != EOrderStatusHotel.PAYMENT_NO.getCode() && DateUtil.nowDate().getTime() > startTime.getTime()) {
            ExpUtil.throwEx("入住时间已到，不能取消！");
        }

        // 修改订单状态
        HotelOrder ord = new HotelOrder();
        // 如果已发货就让商家审核
        if (status == EOrderStatusHotel.PAYMENT_NO.getCode()) {
            // 如果未支付就将状态改为已关闭
            ord.setStatus(EOrderStatusHotel.CLOSE_YES.getCode());
            ord.setCloseType(EOrderCloseType.CANCEL.getCode());
        } else if (status == EOrderStatusHotel.PAYMENT_YES.getCode()
            || status == EOrderStatusHotel.CHECK_NO.getCode()) {
            // 如果已支付就将状态改为退款中
            ord.setStatus(EOrderStatus.REFUND_ING.getCode());
            ord.setCloseType(EOrderCloseType.CANCEL.getCode());
            ord.setIsCheck(EGeneralYesNo.NO.getCode());
            ord.setNoRefund(IdUtil.uuid());
            ord.setIsRefunds(ERefundsStatus.ING.getCode());
            ord.setPriceRefund(findByNo.getPrice());
        }
        ord.setId(findByNo.getId());
        updatePartialById = hotelOrderService.updateById(ord);
        if (updatePartialById < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        // 获取优惠券ID
        String couponNos = findByNo.getNosCoupon();
        // 如果未付款并且有用优惠券就将优惠券退回
        if (EPayStatus.NO.getCode() == findByNo.getIsPay() && StringUtil.isNotBlankObject(couponNos)) {
            String[] split = couponNos.split(",");
            UserCoupon userCoupon = new UserCoupon();
            userCoupon.setNos(Arrays.asList(split));
            userCoupon.setStatus(EUserCouponStatus.USE_NO.getCode());
            userCouponDaoImpl.updateByNoList(userCoupon);
        }

        // 如果未发货并且已支付就退款
        // 如果已付款就退款
        if (EPayStatus.YES.getCode() == findByNo.getIsPay()) {
            ord.refundInit(findByNo.getNo(), findByNo.getPrice(), ord.getNoRefund(), ord.getPriceRefund(),
                findByNo.getPayType());
            PayUtil.refund(ord, IpConfig.getUrl() + WxConstant.NOTIFY_URL_HOTEL_CANCEL);
        }

        return updatePartialById;
    }

    /**
     * 订单退款
     *
     * @param no
     * @return
     * @throws Exception
     */
    @Override
    public int refund(HotelOrder hotelOrders) throws Exception {
        synchronized (Lock.ORDER_STATUS_HOTEL) {
            return hotelOrderService.refundGo(hotelOrders);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public int refundGo(HotelOrder hotelOrders) throws Exception {
        HotelOrder findByNo = hotelOrderDaoImpl.findByNo(hotelOrders.getNo());

        if (StringUtil.isBlankObject(findByNo)) {
            ExpUtil.throwEx("订单不存在！");
        }
        if (findByNo.getStatus() == EOrderStatusHotel.CLOSE_YES.getCode()
            || findByNo.getStatus() == EOrderStatusHotel.REFUND_ING.getCode()) {
            ExpUtil.throwEx("订单已处理过退款！");
        }
        hotelOrders.updateInit();
        hotelOrders.setStatus(EOrderStatusHotel.REFUND_ING.getCode());
        hotelOrders.setCloseType(EOrderHotelCloseType.REIMBURSE.getCode());
        hotelOrders.setIsCheck(EGeneralYesNo.NO.getCode());
        hotelOrders.setNoRefund(IdUtil.uuid());
        hotelOrders.setIsRefunds(ERefundsStatus.ING.getCode());
        double refundTotal = hotelOrders.getPrice().doubleValue();
        double orderTotal = findByNo.getPrice().doubleValue();
        if (refundTotal > orderTotal) {
            ExpUtil.throwEx("退款金额不能大于订单支付金额！");
        }
        int updateByNo = hotelOrderDaoImpl.updateByNo(hotelOrders);
        if (updateByNo < 1) {
            ExpUtil.throwEx("订单状态修改失败！");
        }

        hotelOrders.refundInit(findByNo.getNo(), findByNo.getPrice(), hotelOrders.getNoRefund(), hotelOrders.getPrice(),
            findByNo.getPayType());
        PayUtil.refund(hotelOrders, IpConfig.getUrl() + WxConstant.NOTIFY_URL_HOTEL_CANCEL);
        return updateByNo;
    }

    /**
     * 查询编号列表
     *
     * @param orderVo
     * @return
     */
    @Override
    public List<String> findNosByVo(HotelOrder orderVo) {
        return hotelOrderDaoImpl.findNosByVo(orderVo);
    }

    /**
     * 将状态改为待评论
     *
     * @param no
     * @return
     * @throws Exception
     */
    @Override
    public int updateStatusToCommentNo(String no) throws Exception {
        synchronized (Lock.ORDER_STATUS_HOTEL) {
            synchronized (Lock.BALANCE_LOG) {
                return hotelOrderService.updateStatusToCommentNoGo(no);
            }
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public int updateStatusToCommentNoGo(String no) throws Exception {
        HotelOrder findByNo = hotelOrderDaoImpl.findByNo(no);
        if (StringUtil.isBlankObject(findByNo)) {
            return 0;
        }

        if (findByNo.getStatus() != EOrderStatusHotel.CHECK_NO.getCode()
            && findByNo.getStatus() != EOrderStatusHotel.CHECK_YES.getCode()) {
            return 0;
        }

        HotelOrder hotelOrder = new HotelOrder();
        hotelOrder.setNo(no);
        hotelOrder.setStatus(EOrderStatusHotel.COMMENT_NO.getCode());
        int updateByNo = hotelOrderDaoImpl.updateByNo(hotelOrder);
        if (updateByNo < 1) {
            return 0;
        }

        // 添加分成
        Brokerage info = brokerageService.getInfo();
        if (info.getStatus() != EGeneralStatus.NORMAL.getCode()) {
            return updateByNo;
        }
        // 获取购买用户的上级用户
        User top = userDao.findTopByNo(findByNo.getNoUser());
        if (StringUtil.isBlankObject(top) || StringUtil.isNotBlankObject(top.getFirstOrderNo())) {
            return updateByNo;
        }

        // 计算佣金
        // 佣金
        BigDecimal price = null;
        if (info.getType() == 1) {
            price = info.getTotal();
        } else if (info.getType() == 2) {
            // 订单金额
            BigDecimal orderTotal = findByNo.getPrice();
            // 分佣百分比上限
            BigDecimal totalTop = info.getTotalTop();
            price = ArithUtil.mulRoundDown(info.getTotal(), orderTotal, 2);
            double doubleValue = price.doubleValue();
            if (doubleValue > totalTop.doubleValue()) {
                price = totalTop;
            }
        }
        if (price.doubleValue() <= 0) {
            return updateByNo;
        }
        // 修改佣金
        BigDecimal add = top.getBalance().add(price);
        User member = new User();
        member.setId(top.getId());
        member.setFirstOrderNo(findByNo.getNo());
        member.setFirstOrderType(EFirstOrderType.HOTEL.getCode());
        member.setBalance(add);
        member.setBalanceSum(top.getBalanceSum().add(price));
        int updateMember = userDao.updateById(member);
        if (updateMember < 1) {
            ExpUtil.throwEx("签收失败,上级用户添加分成失败！");
        }

        HotelOrderRoom findByNoHotelOrder = hotelOrderRoomDaoImpl.findByNoHotelOrder(no);
        // 添加佣金记录
        BalanceLog balanceLog = new BalanceLog();
        balanceLog.insertInit("分销到账", top.getId(), price, top.getBalance(), EBalanceType.DIVIDE.getCode(),
            EBalanceDivideType.HOTEL.getCode(), EBalanceTotalType.COMMISSION.getCode(), EBalanceCount.ADD.getCode(),
            findByNo.getNo(), findByNo.getNo() + "-入住完成通知");
        balanceLog.setOrderNo(findByNo.getNo());
        balanceLog.setMark(findByNoHotelOrder.getNameHotel() + "-" + findByNoHotelOrder.getNameRoom());
        int insert = balanceLogDaoImpl.insert(balanceLog);
        if (insert < 1) {
            ExpUtil.throwEx("签收失败,上级用户添加分成失败！");
        }
        // 发送消息
        messageSystemService.send(ConstantMessageSystemTemplate.getBalanceAccount(price, balanceLog.getCreatedAt()),
            EMessageSystemType.BALANCE.getCode(), EBalanceTotalType.COMMISSION.getCode(), balanceLog.getId() + "", top);
        return updateByNo;
    }

    /**
     * 下单
     *
     * @param orderParam
     * @return
     * @throws Exception
     */
    @Override
    public String orders(OrderParam orderParam) throws Exception {
        String orders = null;
        List<OrderStoreParam> orderStoreParams = orderParam.getOrderStoreParams();

        synchronized (Lock.ORDER_STATUS) {
            orders = hotelOrderService.orders(orderParam, orderStoreParams);
        }
        return orders;
    }

    @Transactional(rollbackFor = Throwable.class)
    public String orders(OrderParam orderParam, List<OrderStoreParam> orderStores) throws Exception {
        String noShop = IdUtil.uuid();
        StringBuilder orders = new StringBuilder();

        for (OrderStoreParam orderStore : orderStores) {
            orders.append(hotelOrderService.ordersGo(orderParam, orderStore, noShop)).append(",");
        }
        return orders.substring(0, orders.length() - 1);
    }

    @Transactional(rollbackFor = Throwable.class)
    public String ordersGo(OrderParam orderParam, OrderStoreParam orderStoreParam, String noShop) throws Exception {
        HotelOrder order = new HotelOrder();
        // 订单编号
        String uuid = IdUtil.uuid();
        // 优惠券编号
        String couponNos = orderStoreParam.getCouponNos();

        BaseUser member = TokenUtil.getUser();
        order.insertInit();
        // order.setNoShop(noShop);
        order.setNo(uuid);
        order.setNoUser(member.getId());
        order.setNosCoupon(couponNos);
        order.setStartTime(orderStoreParam.getStartTime());
        order.setEndTime(orderStoreParam.getEndTime());
        order.setDay((int)DateUtil.getDate(orderStoreParam.getStartTime(), orderStoreParam.getEndTime()));

        // 店主编号
        String storeUserNo = null;
        // 店铺编号
        String storeNo = null;
        // 入住天数
        long date = DateUtil.getDate(orderStoreParam.getStartTime(), orderStoreParam.getEndTime());
        BigDecimal datePri = new BigDecimal(String.valueOf(date));
        // 商品总价
        BigDecimal pri = new BigDecimal("0");
        // 订单参数
        List<OrderGoodsParam> param = orderStoreParam.getOrderGoodsParams();
        // 要添加的商品订单数据
        List<HotelOrderRoom> ods = new ArrayList<>();
        // 要添加的订单用户数据
        List<HotelOrderUser> odUsers = new ArrayList<>();
        // 优惠券使用的商品
        Map<String, CouponUseGoodsParam> cugps = new HashMap<>();

        // 验证商品参数是否正确
        for (OrderGoodsParam orderGoodsParam : param) {
            HotelRoom g = hotelRoomDaoImpl.findByNo(orderGoodsParam.getGoodSpecsNo());
            // 商品数量
            Integer goodNum = orderGoodsParam.getGoodNum();
            // 判断商品规格是否存在
            if (StringUtil.isBlankObject(g)) {
                ExpUtil.throwEx("房间不存在！");
            }
            if (g.getStatus() == EGeneralStatus.DISABLE.getCode()) {
                ExpUtil.throwEx("房间已禁用！");
            }

            // Goods g = goodsDaoImpl.findById(gs.getGoodId());
            // if (StringUtil.isBlankObject(g)) {
            // ExpUtil.throwEx("商品不存在！");
            // }
            // if (g.getStatus() == EGeneralStatus.DISABLE.getCode()) {
            // ExpUtil.throwEx("商品已禁用！");
            // }
            String goodsNo = g.getNo();
            CouponUseGoodsParam couponUseGoodsParam = cugps.get(goodsNo);
            if (StringUtil.isBlankObject(couponUseGoodsParam)) {
                CouponUseGoodsParam cugp = new CouponUseGoodsParam();
                cugp.setUseGoodsNo(goodsNo);
                cugp.setTotal(g.getPrice());
                cugps.put(goodsNo, cugp);
            } else {
                couponUseGoodsParam.setTotal(couponUseGoodsParam.getTotal().add(g.getPrice()));
            }

            Hotel findByNo = hotelDaoImpl.findByNo(g.getNoHotel());
            if (StringUtil.isBlankObject(storeNo)) {
                storeUserNo = findByNo.getUserNo();
                storeNo = findByNo.getNo();
                order.setNoMerchant(storeUserNo);
            } else {
                if (!storeNo.equals(findByNo.getNo())) {
                    ExpUtil.throwEx("所有房间必须是同一个店铺的");
                }
            }

            // 计算价格
            // 商品单价
            BigDecimal p = g.getPrice();
            // 此规格商品总价
            BigDecimal multiply = p.multiply(new BigDecimal(String.valueOf(goodNum))).multiply(datePri);
            // 订单总价累计
            pri = pri.add(multiply);

            // 添加商品订单数据
            String mobile = orderGoodsParam.getMobile();
            HotelOrderRoom orderGoods = new HotelOrderRoom();
            orderGoods.insertInit();
            orderGoods.setNoHotelOrder(order.getNo());
            orderGoods.setNameHotel(findByNo.getName());
            orderGoods.setNameRoom(g.getName());
            orderGoods.setDescsRoom(g.getDescs());
            orderGoods.setPrice(p);
            orderGoods.setNum(goodNum);
            orderGoods.setMobile(mobile);
            orderGoods.setImg(findByNo.getImg());
            orderGoods.setProvince(findByNo.getProvince());
            orderGoods.setCity(findByNo.getCity());
            orderGoods.setArea(findByNo.getArea());
            orderGoods.setAddress(findByNo.getAddress());
            orderGoods.setTargetX(findByNo.getTargetX());
            orderGoods.setTargetY(findByNo.getTargetY());
            ods.add(orderGoods);

            List<OrderUserParam> orderUsers = orderGoodsParam.getOrderUsers();
            for (OrderUserParam hotelOrderUser : orderUsers) {
                HotelOrderUser user = new HotelOrderUser();
                user.insertInit();
                user.setNoHotelOrder(uuid);
                user.setName(hotelOrderUser.getName());
                user.setMobile(hotelOrderUser.getMobile());
                odUsers.add(user);
            }
        }

        // 使用优惠券
        Collection<CouponUseGoodsParam> values = cugps.values();
        List<CouponUseGoodsParam> CouponUseGoodsParams = new ArrayList<>();
        for (CouponUseGoodsParam couponUseGoodsParam : values) {
            CouponUseGoodsParams.add(couponUseGoodsParam);
        }
        CouponUseResponse orderUse =
            couponService.orderUse(couponNos, EModuleNo.HOTEL.getCode(), storeNo, CouponUseGoodsParams, pri);
        order.setPrice(orderUse.getTotal());
        order.setNosCoupon(orderUse.getCouponNos());
        order.setPriceCouponSplit(orderUse.getTotalSplit());

        // 优惠了多少钱
        BigDecimal subBig = ArithUtil.subBig(pri, order.getPrice());
        order.setPriceCoupon(subBig);
        order.setPriceOriginal(pri);

        // 添加订单
        int insert = hotelOrderDaoImpl.insert(order);
        if (insert < 1) {
            ExpUtil.throwEx("添加订单信息失败，请重试！");
        }

        int insertList = hotelOrderRoomDaoImpl.insertList(ods);
        if (insertList != ods.size()) {
            ExpUtil.throwEx("添加订单房间信息失败，请重试！");
        }

        insertList = hotelOrderUserDaoImpl.insertList(odUsers);
        if (insertList != odUsers.size()) {
            ExpUtil.throwEx("添加订单用户信息失败，请重试！");
        }
        return uuid;
    }

    /**
     * 用户首页统计
     *
     * @return
     */
    @Override
    public Map<String, Integer> countUser(HotelOrderVo hotelOrder) {
        return hotelOrderDaoImpl.countUser(hotelOrder);
    }

    /**
     * 通过no更新状态(局部更新)
     *
     * @param hotelOrder
     * @return
     */
    @Override
    public int updateStatus(HotelOrder hotelOrder) {
        List<String> nos = hotelOrder.getNos();
        String[] arr = new String[nos.size()];
        Integer status = hotelOrder.getStatus();
        int targetStatus = -1;
        if (status == EOrderStatusHotel.CLOSE_YES.getCode()) {
            targetStatus = 0;
        } else if (status == EOrderStatusHotel.CHECK_YES.getCode()) {
            targetStatus = EOrderStatusHotel.CHECK_NO.getCode();
        }
        synchronized (Lock.ORDER_STATUS_HOTEL) {
            List<HotelOrder> findByNos = hotelOrderDaoImpl.findByNos(nos.toArray(arr));
            List<String> noList = new ArrayList<>();
            for (HotelOrder ho : findByNos) {
                Integer s = ho.getStatus();
                if (s == 0 || s == targetStatus) {
                    noList.add(ho.getNo());
                }
            }

            HotelOrder hos = new HotelOrder();
            hos.updateInit();
            hos.setStatus(status);
            hos.setNos(noList);

            return hotelOrderDaoImpl.updateByNoList(hos);
        }
    }

}